import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:islandingclub/net/result_data.dart';
import 'package:islandingclub/net/result_error.dart';

/// 基于Dio二次封装网络请求，单例模式
class DioHttpClient {
  /// 服务器接口地址公有部分
  static final String _baseUrl = 'https://xiaodu.maliapi.com';

  /// 连接超时、请求超时、响应超时 ，默认统一值
  static const int _defaultTimeout = 30 * 1000;

  /// 请求方式
  static const String _get = "get";
  static const String _post = "post";

  /// Dio实例
  Dio _dio;

  ///参数实例
  BaseOptions _baseOptions;

  /// 本类实例
  static DioHttpClient _instance;

  /// 构造函数私有化（单例模式）
  DioHttpClient._internal() {
    // 初始化 http 基本
    _baseOptions = BaseOptions(
        baseUrl: _baseUrl,
        connectTimeout: _defaultTimeout,
        sendTimeout: _defaultTimeout,
        receiveTimeout: _defaultTimeout,
        responseType: ResponseType.plain,
        validateStatus: (status) {
          // 不使用http状态码判断状态，使用AdapterInterceptor来处理（适用于标准REST风格）
          if (status >= HttpStatus.ok && status < HttpStatus.multipleChoices) {
            return true;
          }
          return false;
        },
        headers: {
          Headers.contentTypeHeader: Headers.jsonContentType,
          Headers.acceptHeader: '*/*',
          'PLATFORM': Platform.operatingSystem,
        });
    // Dio实例
    _dio = new Dio(_baseOptions);
    // 日志拦截器
    _dio.interceptors.add(LogInterceptor(requestBody: true));
    // 自定义拦截器
    _dio.interceptors.add(InterceptorsWrapper(
        // 拦截请求发送事件（如添加 token、versionCode、platformType 等）
        onRequest: (RequestOptions options) async {
      // Do something before request is sent
      return options; //continue
      // If you want to resolve the request with some custom data，
      // you can return a `Response` object or return `dio.resolve(data)`.
      // If you want to reject the request with a error message,
      // you can return a `DioError` object or return `dio.reject(errMsg)`
    },

        // 拦截请求响应事件（如数据重组，便于业务代码中快速处理调用）
        onResponse: (Response response) async {
      // Do something with response data
      return response; // continue
    },

        // 拦截请求失败事件（如添加统一的错误提示 或 统一的错误处理逻辑等）
        onError: (DioError e) async {
      // Do something with response error
      return e; //continue
    }));
  }

  static DioHttpClient getInstance() {
    if (_instance == null) {
      _instance = DioHttpClient._internal();
    }
    return _instance;
  }

  Future<Map<String, dynamic>> _request(
    String path, {
    data,
    Map<String, dynamic> queryParameters,
    CancelToken cancelToken,
    Options options,
    ProgressCallback onSendProgress,
    ProgressCallback onReceiveProgress,
  }) async {
    Response response;
    try {
      response = await _dio.request(path,
          data: data,
          queryParameters: queryParameters,
          cancelToken: cancelToken,
          options: options,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress);

      Map<String, dynamic> respData = json.decode(response.data);
      ResultData resultData = ResultData.fromJson(respData);
      if (resultData.isSuccess) {
        return Future.value(respData);
      } else {
        throw ResultError.fromJson(resultData);
      }
    } on DioError catch (e) {
      print('请求 url：$_baseUrl$path');
      switch (e.type) {
        case DioErrorType.CANCEL:
          print('请求取消');
          break;
        case DioErrorType.CONNECT_TIMEOUT:
          print('连接超时');
          break;
        case DioErrorType.SEND_TIMEOUT:
          print('请求超时');
          break;
        case DioErrorType.RECEIVE_TIMEOUT:
          print('响应超时');
          break;
        case DioErrorType.RESPONSE:
          print('服务器异常');
          print(e.toString());
          break;
        default:
          print('未知错误');
          print(e.toString());
          break;
      }
      return Future.error(e);
    } on ResultError catch (e) {
      print('请求 url：$_baseUrl$path');
      print('业务错误');
      return Future.error(e);
    }
  }

  Future<Map<String, dynamic>> get(
    String path, {
    Map<String, dynamic> queryParameters,
    Options options,
    CancelToken cancelToken,
    ProgressCallback onSendProgress,
    ProgressCallback onReceiveProgress,
  }) {
    options == null ? options = Options(method: _get) : options.method = _get;
    return _request(path,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
  }

  Future<Map<String, dynamic>> post(
    String path, {
    data,
    Map<String, dynamic> queryParameters,
    Options options,
    CancelToken cancelToken,
    ProgressCallback onSendProgress,
    ProgressCallback onReceiveProgress,
  }) {
    options == null ? Options(method: _post) : options.method = _post;
    return _request(path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
  }
}
